<?php

namespace App\Common\Traits;

use Hyperf\Contract\ValidatorInterface;

trait JsonStringCastTrait
{
    /**
     * Determine if the given value is a valid JSON string.
     *
     * @param  mixed  $value
     * @return bool
     */
    protected function isJsonString($value): bool
    {
        if (!is_string($value)) {
            return false;
        }
        json_decode($value);
        return json_last_error() === JSON_ERROR_NONE;
    }

    /**
     * Override validation data to decode JSON string fields into arrays.
     *
     * Usage: Define an array property $jsonFields in your FormRequest,
     * containing the field names that should be transformed.
     *
     * @return array
     */
    public function validationData(): array
    {
        $data = parent::validationData();

        if (property_exists($this, 'jsonFields') && is_array($this->jsonFields)) {
            foreach ($this->jsonFields as $field) {
                if (isset($data[$field]) && $this->isJsonString($data[$field])) {
                    $decoded = json_decode($data[$field], true);
                    // only replace if decoded is array or object
                    if (is_array($decoded) || is_object($decoded)) {
                        $data[$field] = $decoded;
                    }
                }
            }
        }
        return $data;
    }

    /**
     * 在验证器实例创建后，添加自定义占位符替换器
     */
    public function withValidator(ValidatorInterface $validator)
    {
        foreach (['required'] as $ruleName) {
            $validator->addReplacer($ruleName, function (
                string $message,
                string $attribute,
                string $rule,
                array $parameters
            ) {
                // 匹配所有数字下标，如 users.2.email 或 matrix.1.3
                if (preg_match_all('/\.(\d+)(?:\.|$)/', $attribute, $matches)) {
                    $indexes = array_map(fn($v) => (int)$v + 1, $matches[1]);

                    // 一维／二维通用 :i
                    if (strpos($message, ':i') !== false) {
                        return str_replace(':i', (string)$indexes[0], $message);
                    }
                    // 行索引用 :r
                    if (strpos($message, ':r') !== false && count($indexes) === 1) {
                        return str_replace(':r', (string)$indexes[0], $message);
                    }
                    // 矩阵同时替换 :r 和 :c
                    if (strpos($message, ':r') !== false && strpos($message, ':c') !== false) {
                        return str_replace(
                            [':r', ':c'],
                            [(string)$indexes[0], (string)$indexes[1]],
                            $message
                        );
                    }
                }

                return $message;
            });
        }
    }
}